package com.spider.oss;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.*;
import com.spider.entity.CmsCertEntity;
import com.spider.mapper.OssMapper;
import com.spider.mapper.OssWebMapper;
import com.spider.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

@Component
@Slf4j
public class OssJavaSdkQuickStart {

    @Autowired
    OssMapper ossMapper;
    @Autowired
    OssWebMapper ossWebMapper;
    @Autowired
    OssServiceImpl ossService;
    /** 生成一个唯一的 Bucket 名称 */
    public static String generateUniqueBucketName(String prefix) {
        // 获取当前时间戳
        String timestamp = java.lang.String.valueOf(System.currentTimeMillis());
        // 生成一个 0 到 9999 之间的随机数
        Random random = new Random();
        int randomNum = random.nextInt(10000); // 生成一个 0 到 9999 之间的随机数
        // 连接以形成一个唯一的 Bucket 名称
        return prefix + "-" + timestamp + "-" + randomNum;
    }


    public static List<FileInfo> listFilesInFolder(String folderPath,OSS ossClient,String bucketName) {
        log.info("进入listFilesInFolder方法");
        List<FileInfo> fileInfos = new ArrayList<>();
        String prefix = folderPath.endsWith("/") ? folderPath : folderPath + "/";
        String nextMarker = null;
        boolean isTruncated;
        do {
            ListObjectsRequest request = new ListObjectsRequest(bucketName)
                    .withPrefix(prefix)
                    .withMarker(nextMarker);
            ObjectListing listing = ossClient.listObjects(request);
            List<OSSObjectSummary> summaries = listing.getObjectSummaries();

            for (OSSObjectSummary summary : summaries) {
                if (!summary.getKey().equals(prefix)) {
                    String fileName = summary.getKey().substring(prefix.length());
                    String url = generateUrl(fileName,folderPath+"/");
                    FileInfo fileInfo =new FileInfo();
                    fileInfo.setFilename(fileName);
                    fileInfo.setUrl(url);
                    fileInfos.add(fileInfo);
                }
            }

            nextMarker = listing.getNextMarker();
            isTruncated = listing.isTruncated();
        } while (isTruncated);
        log.info("fileInfos长度为"+fileInfos.size());
        return fileInfos;
    }

    public static List<FileInfo> listFilesAndCreateSymlinks(
            String folderPath,
            OSS ossClient,
            String bucketName,
            String symlinkFolder) { // 新增参数：软链接存放目录

        log.info("开始遍历并创建软链接，源目录: {}, 目标目录: {}", folderPath, symlinkFolder);
        List<FileInfo> fileInfos = new ArrayList<>();
        String prefix = folderPath.endsWith("/") ? folderPath : folderPath + "/";
        String nextMarker = null;
        boolean isTruncated;

        try {
            do {
                // 1. 分页列出OSS文件
                ListObjectsRequest request = new ListObjectsRequest(bucketName)
                        .withPrefix(prefix)
                        .withMarker(nextMarker);
                ObjectListing listing = ossClient.listObjects(request);
                List<OSSObjectSummary> summaries = listing.getObjectSummaries();

                for (OSSObjectSummary summary : summaries) {
                    String objectKey = summary.getKey();
                    System.out.println(objectKey);
                    // 跳过目录本身
                    if (objectKey.equals(prefix)) continue;

                    // 2. 生成软链接路径（保留目录结构）
                    String relativePath = objectKey.substring(prefix.length());
                    String simpleName = OssUtil.extractFileNamePart(relativePath);
                    if(StringUtil.isNotEmpty(simpleName)){
                        String symlinkKey = symlinkFolder + "/" + simpleName;
                        // 3. 创建软链接
                        createSymlinkWithRetry(ossClient, bucketName, symlinkKey, objectKey);
                        // 4. 收集文件信息（指向软链接）
                        String fileName = new File(objectKey).getName();
                        String url = generateUrl(symlinkKey);
                        FileInfo fileInfo =new FileInfo();
                        fileInfo.setFilename(fileName);
                        fileInfo.setUrl(url);
                        fileInfo.setUpdate(new Date());
                        fileInfos.add(fileInfo);
                    }
                }

                nextMarker = listing.getNextMarker();
                isTruncated = listing.isTruncated();
                //break;
            } while (isTruncated);

        } catch (OSSException | ClientException e) {
            log.error("OSS操作失败: {}", e.getMessage());
        }

        log.info("共处理{}个文件，生成{}个软链接", fileInfos.size(), fileInfos.size());
        return fileInfos;
    }

    /**
            * 创建软链接（含重试机制）
            */
    private static void createSymlinkWithRetry(OSS ossClient, String bucketName,
                                               String symlinkKey, String targetKey) {
        int maxRetries = 3;
        for (int i = 0; i < maxRetries; i++) {
            try {
                // 检查软链接是否已存在
                if (ossClient.doesObjectExist(bucketName, symlinkKey)) {
                    log.warn("软链接已存在，跳过创建: {}", symlinkKey);
                    return;
                }

                // 创建软链接请求
                CreateSymlinkRequest request = new CreateSymlinkRequest(
                        bucketName,
                        symlinkKey,
                        targetKey
                );

                // 设置公共读权限（与目标文件一致）
                ObjectMetadata metadata = new ObjectMetadata();
                metadata.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.PublicRead);
                request.setMetadata(metadata);

                ossClient.createSymlink(request);
                log.debug("成功创建软链接: {} -> {}", symlinkKey, targetKey);
                return;

            } catch (OSSException e) {
                if (e.getErrorCode().equals("SymlinkTargetNotExist")) {
                    log.error("目标文件不存在，无法创建软链接: {}", targetKey);
                    break;
                }
                log.warn("创建软链接失败，重试 {}/3. 原因: {}", i+1, e.getMessage());
            } catch (ClientException e) {
                log.warn("客户端异常，重试 {}/3. 原因: {}", i+1, e.getMessage());
            }

            try { Thread.sleep(1000); } catch (InterruptedException ex) {}
        }
    }


    public List<FileInfo> uploadLocalFile(
            String ossFolderPath,
            String localDirPath,
            OSS ossClient,
            String bucketName,
            int num
    ) throws ClientException {
        log.info("进入uploadLocalFile方法");
        List<FileInfo> fileInfos = new ArrayList<>();
        File rootDir = new File(localDirPath);

        if (!rootDir.exists() || !rootDir.isDirectory()) {
            log.error("无效的本地目录: {}", localDirPath);
            return fileInfos;
        }

        int processedCount = 0;
        try {
            try (var stream = Files.walk(rootDir.toPath())) {
                for (Path filePath : (Iterable<Path>) stream::iterator) {
                    if (Files.isRegularFile(filePath)) {
                        if (processedCount >= num) {
                            break;
                        }
                        File file = filePath.toFile();
                        try {
                            // 生成OSS对象路径（保留目录结构）
                            String relativePath = rootDir.toPath()
                                    .relativize(filePath)
                                    .toString()
                                    .replace("\\", "/");
                            String simpleName = OssUtil.extractFileNamePart(relativePath);
                            String objectName = ossFolderPath + "/" + simpleName;

                            // 1. 上传原始文件
                            ossClient.putObject(bucketName, objectName, file);
                            if (StringUtil.isNotEmpty(simpleName)) {
                                String url = generateUrl(objectName);
                                FileInfo fileInfo = new FileInfo();
                                CmsCertEntity cmsCertEntity = OssUtil.convertCmsCert(relativePath);
                                fileInfo.setFilename(file.getName());
                                fileInfo.setUrl(url);
                                fileInfo.setBatch(cmsCertEntity.getBatch());
                                fileInfo.setUpdate(new Date(file.lastModified()));
                                fileInfos.add(fileInfo);
                                cmsCertEntity.setUrl(url);
                                cmsCertEntity.setDelFlag(0);
                                cmsCertEntity.setType(0);
                                cmsCertEntity.setName(simpleName);
                                cmsCertEntity.setCreateTime(new Date());
                                List<CmsCertEntity> cmsCertEntities = ossWebMapper.selectByBatch(cmsCertEntity.getBatch());
                                if (cmsCertEntities == null || cmsCertEntities.size() == 0) {
                                    ossWebMapper.saveFile(cmsCertEntity);
                                }
                                List<FileInfo> fileInfos1 = ossMapper.selectByBatch(cmsCertEntity.getBatch());
                                if (fileInfos1 == null || fileInfos1.size() == 0) {
                                    ossMapper.saveFile(fileInfo);
                                }
                                if (!file.delete()) {
                                    log.error("本地文件删除失败：{}", file.getAbsolutePath());
                                }
                                processedCount++;
                            }
                        } catch (OSSException | ClientException e) {
                            log.error("OSS操作失败：{}", e.getMessage());
                        } catch (Exception e) {
                            log.error("文件处理异常：{}", e.getMessage());
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.error("目录遍历失败：{}", e.getMessage());
            throw new ClientException(e);
        }
        return fileInfos;
    }


    // 创建COA_AUTO2的软链接副本
    public List<FileInfo> createAuto2Symlinks(List<FileInfo> originFiles, OSS ossClient, String bucketName) {
        List<FileInfo> auto2Files = new ArrayList<>();
        String targetFolder = "COA_AUTO2";

        for (FileInfo originFile : originFiles) {
            try {
                // 解析原始文件路径
                String originKey = generateUrl(originFile.getUrl());

                // 生成软链接路径（保留目录结构）
                String symlinkKey = targetFolder + "/" + originKey.replaceFirst("^COA_DOC/", "");

                // 创建软链接
                createSymlink(ossClient, bucketName, symlinkKey, originKey);

                // 生成新文件信息
                FileInfo auto2File =new FileInfo();
                auto2File.setFilename(originFile.getFilename());
                auto2File.setUrl( generateUrl(bucketName, symlinkKey));
                auto2File.setUpdate(originFile.getUpdate());
                auto2Files.add(auto2File);
            } catch (Exception e) {
                log.error("创建软链接失败：{}", e.getMessage());
            }
        }
        return auto2Files;
    }


    // 使用最新SDK方法创建软链接
    private void createSymlink(OSS ossClient, String bucketName,
                               String symlinkKey, String targetObjectKey) {
        try {
            CreateSymlinkRequest request = new CreateSymlinkRequest(
                    bucketName,
                    symlinkKey,  // 软链接路径
                    targetObjectKey  // 目标文件路径
            );

            // 可选设置（根据需求）
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setHeader("x-oss-forbid-overwrite", "false"); // 允许覆盖同名文件
            metadata.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.PublicRead);
            request.setMetadata(metadata);

            ossClient.createSymlink(request);
            log.debug("软链接创建成功：{} -> {}", symlinkKey, targetObjectKey);
        } catch (OSSException e) {
            log.error("OSS错误: Code={}, Message={}", e.getErrorCode(), e.getMessage());
        } catch (ClientException e) {
            log.error("客户端错误: {}", e.getMessage());
        }
    }



    private static String generateUrl(String name,String folder) {
        String prefix = "https://alta-coa.oss-cn-beijing.aliyuncs.com/"+folder;
        return prefix +name;
    }

    private static String generateUrl(String folder) {
        String prefix = "https://alta-coa.oss-cn-beijing.aliyuncs.com/"+folder;
        return prefix;
    }
}
